// 解析dom
const State = {
    tagStart: 1,
    tagTxt: 2,
    tagEnd: 3
}
class Parser {
    constructor(input) {
        this.input = input
        this.curLoc = 0;
        this.len = input.length;
        this.tags = [];

    }
    parser() {
        this.dom();
    }

    /**
     * 处理开始节点
     * @param {*} curNode  当前节点
     * @param {*} objNode  需要插入的节点
     */
    handleStartTag(curNode, objNode) {
        if (curNode.children === undefined || curNode.children.length === 0) {
            curNode.children = [objNode];
        } else {
            const state = curNode.children.every(item => item.state === State.tagEnd);
            if (state) {
                curNode.children.push(objNode)
            } else {
                curNode.children.forEach(item => {
                    if (item.state === State.tagStart) {
                        this.handleStartTag(item, objNode);
                    }
                })
            }
        }
    }
    /**
     * 处理内容节点
     * @param {*} curNode  当前节点
     * @param {*} objNode  需要插入的节点
     */
    handleTagTxt(curNode, objNode) {
        if (curNode.children === undefined || curNode.children.length === 0) {
            curNode.children = objNode.children;
        } else {
            curNode.children.forEach(item => {
                if (item.state === State.tagStart) {
                    this.handleTagTxt(item, objNode);
                }
            })
        }
    }

    /**
     * 处理结束节点
     * @param {*} curNode  当前节点
     * @param {*} objNode  需要插入的节点
     */
    handleEndTag(curNode, objNode) {
        if (Array.isArray(curNode.children)) {
            const state = curNode.children.every(item => item.state === State.tagEnd);
            if (state) {
                curNode.state = State.tagEnd;
            } else {
                curNode.children.forEach(item => {
                    if (item.state === State.tagStart) {
                        this.handleEndTag(item, objNode);
                    }
                })
            }
        } else {
            curNode.state = State.tagEnd;
        }

    }

    /**
     * 处理树
     * @param {*} preNode // 上一个节点
     * @param {*} curNode // 当前节点 
     * @param {*} objNode // 需要插入的节点
     */
    handleTree(rootObj, objNode) {
        if (objNode.state === State.tagStart) {
            this.handleStartTag(rootObj, objNode);
        } else if (objNode.state === State.tagTxt) {
            this.handleTagTxt(rootObj, objNode);
        } else {
            this.handleEndTag(rootObj, objNode);
        }

    }
    /**
     * 获取 标签的属性
     * @param {*} tags 
     * @returns 
     */
    handleAttr(tags) {
        let tag;
        let attr = {};
        const reg = /\s/g;
        tags = tags.trim();
        const arr = tags.split(reg);
        if (arr) {
            arr.forEach((item, idx) => {
                idx === 0 && (tag = item);
                if (idx === 0) {
                    tag = item;
                } else {
                    if (item.indexOf('=') !== -1) {
                        const att = item.split(/=/g);
                        attr[att[0]] = att[1];
                    } else {
                        attr[item] = true;
                    }
                }
            });
        } else {
            tag = tags;
        }
        return {
            tag,
            attr
        }
    }

    // 解析内容
    getTags(ch) {
        if (ch === 60) {
            if (this.input.charCodeAt(this.curLoc + 1) === 47) // </ 结束标签
            {
                const idx = this.input.indexOf('>', this.curLoc);
                if (idx !== -1) {
                    const obj = {
                        tag: '',
                        attr: '',
                        state: State.tagEnd,
                        children: undefined
                    }
                    this.tags.forEach(item => {
                        if (item.state === State.tagStart) {
                            this.handleTree(item, obj);
                        }
                    })

                    this.curLoc = idx + 1;
                } else {
                    this.curLoc++
                }


            } else { // 表示开始标签
                const idx = this.input.indexOf('>', this.curLoc);
                if (idx !== -1) {
                    let tags;

                    let state = void 0;
                    if (this.input.charCodeAt(idx - 1) === 47) {
                        tags = this.input.slice(this.curLoc + 1, idx - 1);
                        this.curLoc = idx + 2;
                        state = State.tagEnd;
                    } else {
                        tags = this.input.slice(this.curLoc + 1, idx)
                        this.curLoc = idx + 1;
                        state = State.tagStart;
                    }
                    const TagAttr = this.handleAttr(tags);
                    const obj = {
                        tag: TagAttr.tag,
                        attr: TagAttr.attr,
                        state,
                        children: undefined
                    }


                    if (this.tags.length === 0) {
                        this.tags.push(obj);
                    } else {
                        const state = this.tags.every(item => item.state === State.tagStart);
                        if (state) {
                            this.tags.forEach(item => {
                                if (item.state === State.tagStart) {
                                    this.handleTree(item, obj);
                                }
                            })
                        } else {
                            this.tags.push(obj);
                        }

                    }
                } else {
                    this.curLoc++
                }
            }
        } else {
            const idx = this.input.indexOf('<', this.curLoc);
            if (idx !== -1) {
                if (this.input.slice(this.curLoc, idx).charCodeAt() !== 32) {
                    const obj = {
                        tag: '',
                        attr: '',
                        state: State.tagTxt,
                        children: this.input.slice(this.curLoc, idx)
                    }
                    this.tags.forEach(item => {
                        if (item.state === State.tagStart) {
                            this.handleTree(item, obj);
                        }
                    })
                    this.curLoc = idx;
                } else {
                    this.curLoc++;
                }

            } else {
                this.curLoc++;
            }
        }
    }

    dom() {
        while (this.curLoc < this.len) {
            const ch = this.input.charCodeAt(this.curLoc);
            switch (ch) {
                case 10:
                case 13:
                    ++this.curLoc;
                    break;
                default:
                    this.getTags(ch);
                    break;
            }
        }
    }
    getTokens() {
        return this.tags();
    }
}
module.exports = Parser;